import {
  HttpException,
  HttpStatus,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import * as bcrypt from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { InjectRedis } from '@nestjs-modules/ioredis';
import Redis from 'ioredis';
import { UserInfo } from './vo/user-info.vo';
import * as svgCaptcha from 'svg-captcha';
import { v4 as uuidv4 } from 'uuid';
import { formatDateTime } from 'src/utils/day';
import { SysDept } from 'src/entities/sys-dept.entity';
import { SysUser } from 'src/entities/sys-user.entity';
import { SysRole } from 'src/entities/sys-role.entity';
import { UpdateUserDto } from './dto/update-user-admin.dto';
import { CreateUserDto } from './dto/create-user-admin.dto';
import { UserQueryDto } from './dto/query-user-admin.dto';
import { LoginDto } from './dto/login-user-admin.dto';

@Injectable()
export class UserAdminService {
  constructor(
    @InjectRepository(SysUser)
    private userRepository: Repository<SysUser>,
    @InjectRepository(SysRole)
    private roleRepository: Repository<SysRole>,
    @InjectRepository(SysDept)
    private deptRepository: Repository<SysDept>,
    private readonly jwtService: JwtService,
    @InjectRedis() private readonly redis: Redis,
  ) {}
  async create(createUserDto: CreateUserDto): Promise<SysUser> {
    const user = new SysUser();
    Object.assign(user, createUserDto);

    const salt = bcrypt.genSaltSync(10);
    user.password = bcrypt.hashSync(createUserDto.password, salt);

    if (createUserDto.roleIds) {
      user.roles = await this.roleRepository.findByIds(createUserDto.roleIds);
    }

    return this.userRepository.save(user);
  }

  async update(id: number, updateUserDto: UpdateUserDto): Promise<SysUser> {
    const user = await this.userRepository.findOne({
      where: { id, is_deleted: false },
      relations: ['roles'],
    });
    if (!user) {
      throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
    }

    // 保存原密码
    const originalPassword = user.password;

    // 使用对象解构，移除可能存在的password字段，避免密码被修改
    const { password, ...safeUpdateData } = updateUserDto;

    // 只更新安全的字段
    Object.assign(user, safeUpdateData);

    // 确保密码不变
    user.password = originalPassword;
    if (updateUserDto.roleIds) {
      user.roles = await this.roleRepository.findByIds(updateUserDto.roleIds);
    }

    return this.userRepository.save(user);
  }

  async findAll(query: UserQueryDto) {
    const qb = this.userRepository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'role')
      // 添加部门表关联
      .where('user.is_deleted = :isDeleted', { isDeleted: false });

    // 选择需要的字段，排除密码
    qb.select([
      'user.id',
      'user.username',
      'user.nickname',
      'user.gender',
      'user.dept_id',
      'user.avatar',
      'user.mobile',
      'user.status',
      'user.email',
      'user.create_time',
      'user.update_time',
      'role',
    ]);

    if (query.username) {
      qb.andWhere('user.username LIKE :username', {
        username: `%${query.username}%`,
      });
    }

    if (query.nickname) {
      qb.andWhere('user.nickname LIKE :nickname', {
        nickname: `%${query.nickname}%`,
      });
    }

    if (query.mobile) {
      qb.andWhere('user.mobile LIKE :mobile', {
        mobile: `%${query.mobile}%`,
      });
    }

    if (query.status !== undefined) {
      qb.andWhere('user.status = :status', { status: query.status });
    }

    // 添加部门ID查询条件 - 查询该部门及其所有子部门的用户
    if (query.dept_id !== undefined) {
      // 先查询出指定部门及其所有子部门ID
      const targetDept = await this.deptRepository.findOne({
        where: { id: query.dept_id, is_deleted: false },
      });

      if (targetDept) {
        // 查询所有部门
        const allDepts = await this.deptRepository.find({
          where: { is_deleted: false },
        });

        // 获取目标部门及其所有子部门ID
        const deptIds = this.getDeptAndChildrenIds(
          allDepts,
          Number(query.dept_id),
        );

        // 使用IN查询匹配任意部门ID
        qb.andWhere('user.dept_id IN (:...deptIds)', { deptIds });
      } else {
        // 如果部门不存在，仅查询指定部门ID
        qb.andWhere('user.dept_id = :deptId', { deptId: query.dept_id });
      }
    }

    const total = await qb.getCount();
    let users = await qb
      .skip((query.pageNum - 1) * query.pageSize)
      .take(query.pageSize)
      .getMany();

    // 查询所有相关的部门
    const deptIds = users
      .map((user) => user.dept_id)
      .filter((id) => id !== null && id !== undefined);

    const depts = await this.deptRepository.findByIds(deptIds);
    const deptMap = new Map(depts.map((dept) => [Number(dept.id), dept]));

    // 转换 status 从布尔类型到数字类型 (1 或 0)
    users = users.map((user) => {
      const userObj = { ...user } as any;
      userObj.status = userObj.status === true ? 1 : 0;

      // 格式化创建时间
      if (userObj.create_time) {
        userObj.createTime = formatDateTime(userObj.create_time);
        delete userObj.create_time; // 删除原字段
      }

      // 格式化更新时间
      if (userObj.update_time) {
        userObj.updateTime = formatDateTime(userObj.update_time);
        delete userObj.update_time; // 删除原字段
      }

      userObj.roles = userObj.roles.map((role) => {
        return {
          id: role.id,
          code: role.code,
          name: role.name,
        };
      });

      // 添加部门名称
      if (userObj.dept_id && deptMap.has(userObj.dept_id)) {
        userObj.deptName = deptMap.get(userObj.dept_id).name;
      } else {
        userObj.deptName = '';
      }

      return userObj;
    });

    return {
      total,
      list: users,
    };
  }

  async remove(id: number): Promise<void> {
    await this.userRepository.update(id, { is_deleted: true });
  }

  /**
   * @description 用户登录
   */
  async login(loginDto: LoginDto) {
    // 验证验证码
    // const isCaptchaValid = await this.validateCaptcha(loginDto.captchaKey, loginDto.captchaCode);
    // if (!isCaptchaValid) {
    //   throw new HttpException('验证码不正确或已过期', 400);
    // }

    // 查找用户
    const user = await this.userRepository.findOne({
      where: { username: loginDto.username },
      relations: ['roles'],
    });

    if (!user) {
      throw new UnauthorizedException('用户名或密码错误');
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(
      loginDto.password,
      user.password,
    );
    if (!isPasswordValid) {
      throw new UnauthorizedException('用户名或密码错误');
    }

    // 生成token
    const token = this.jwtService.sign({
      id: user.id,
      username: user.username,
      roles: user.roles.map((role) => role.code),
    });

    return {
      accessToken: token,
      tokenType: 'Bearer',
      expiresIn: 3600,
      // userInfo: {
      //   id: user.id,
      //   username: user.username,
      //   nickname: user.nickname,
      //   avatar: user.avatar,
      //   roles: user.roles,
      // },
    };
  }

  /**
   * @description 验证图形验证码
   */
  async validateCaptcha(
    captchaKey: string,
    captchaCode: string,
  ): Promise<boolean> {
    const savedCaptcha = await this.redis.get(captchaKey);
    if (!savedCaptcha) {
      return false;
    }

    // 验证后删除验证码
    await this.redis.del(captchaKey);
    return savedCaptcha.toLowerCase() === captchaCode.toLowerCase();
  }

  /**
   * @description 获取当前登录用户信息
   */
  async getUserInfo(userId: number): Promise<UserInfo> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['roles', 'roles.menus'],
    });

    if (!user) {
      throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
    }

    // 获取用户角色编码
    const roles = user.roles.map((role) => role.code);

    // 获取角色关联的所有菜单权限
    const perms = user.roles
      .flatMap((role) => role.menus)
      .filter((menu) => menu.perm) // 过滤有权限标识的菜单
      .map((menu) => menu.perm)
      .filter((perm, index, self) => self.indexOf(perm) === index); // 去重

    return {
      userId: user.id.toString(),
      username: user.username,
      nickname: user.nickname,
      avatar: user.avatar,
      roles: roles,
      perms: perms,
    };
  }

  /**
   * @description 生成图形验证码
   */
  async generateCaptcha() {
    // 生成验证码
    const captcha = svgCaptcha.create({
      size: 4, // 验证码长度
      noise: 2, // 干扰线条数量
      color: true, // 验证码的字符是否有颜色
      background: '#f0f0f0', // 背景颜色
    });

    // 生成唯一key
    const captchaKey = uuidv4().replace(/-/g, '');

    // 将验证码存入Redis，设置2分钟过期
    await this.redis.set(captchaKey, captcha.text, 'EX', 120);

    // 转换SVG为Base64
    const captchaBase64 = `data:image/svg+xml;base64,${Buffer.from(captcha.data).toString('base64')}`;

    return {
      captchaKey,
      captchaBase64,
    };
  }

  /**
   * @description 用户退出登录
   */
  async logout(userId: number, token: string): Promise<boolean> {
    console.log('Logout:', userId, token);
    // 获取JWT的过期时间
    try {
      const decodedToken = this.jwtService.decode(token) as { exp: number };
      if (decodedToken && decodedToken.exp) {
        // 计算剩余有效期（秒）
        const expiration = decodedToken.exp - Math.floor(Date.now() / 1000);
        if (expiration > 0) {
          // 将token加入黑名单，过期时间与JWT过期时间相同
          const blacklistKey = `user:blacklist:${token}`;
          await this.redis.set(
            blacklistKey,
            userId.toString(),
            'EX',
            expiration,
          );
        }
      }

      // 可以清除用户其他缓存数据（如果有）
      // await this.redis.del(`user:permissions:${userId}`);

      return true;
    } catch (error) {
      console.error('Logout error:', error);
      return false;
    }
  }

  /**
   * @description 根据用户ID获取用户详细信息
   * @param id 用户ID
   */
  async getUserById(id: number) {
    // 查询用户信息，包含角色关联
    const user = await this.userRepository.findOne({
      where: { id, is_deleted: false },
      relations: ['roles'],
    });

    if (!user) {
      throw new HttpException('用户不存在', HttpStatus.NOT_FOUND);
    }

    // 提取角色IDs
    const roleIds = user.roles.map((role) => role.id.toString());

    // 构造前端所需的格式
    const userDetail = {
      id: user.id.toString(),
      username: user.username,
      nickname: user.nickname,
      mobile: user.mobile,
      gender: user.gender,
      avatar: user.avatar,
      email: user.email || '',
      status: user.status === true ? 1 : 0,
      dept_id: user.dept_id ? user.dept_id.toString() : null,
      roleIds: roleIds,
      openId: user.openid,
    };

    return userDetail;
  }

  /**
   * 获取指定部门ID及其所有子部门ID
   * @param allDepts 所有部门列表
   * @param deptId 目标部门ID
   * @returns 部门ID数组
   */
  private getDeptAndChildrenIds(allDepts: SysDept[], deptId: number): number[] {
    // 先添加当前部门ID
    const deptIds = [deptId];

    // 递归查找子部门
    const findChildren = (parentId: number) => {
      const children = allDepts.filter(
        (dept) => Number(dept.parent_id) === parentId,
      );
      children.forEach((child) => {
        deptIds.push(Number(child.id));
        findChildren(Number(child.id));
      });
    };

    findChildren(deptId);
    return deptIds;
  }
}
